Working with File Modes and File Pointers in Python
Course: Python Training
Topic: Working with File Modes and File Pointers
Course Link: Python Training Course at JustAcademy
Demo Link: Register for a Free Course Demo
Website: JustAcademy
1. Introduction to File Handling in Python
File handling allows a Python program to store information permanently, read existing data, update files, and create reports. Unlike variables that normally exist only while a program runs, files can preserve data after the program terminates.
Python provides the built-in open() function to access files. When opening a file, you specify a file mode, which determines whether the file is opened for reading, writing, appending, or binary operations.
A file object also maintains a file pointer, sometimes called a file position. It identifies the position from which the next read or write operation will take place.
Learning Objectives
- Understand how Python opens and accesses files.
- Learn the difference between reading, writing, and appending modes.
- Understand text and binary file modes.
- Use file pointers with
tell() and seek().
- Read and write specific portions of a file.
- Handle file errors and manage resources safely.
2. Opening a File with open()
The open() function creates a file object that can be used to read or modify a file.
file_object = open("example.txt", "r")
In this example, example.txt is the filename and "r" is the mode, which opens the file for reading.
General Syntax
open(file, mode="r", buffering=-1, encoding=None, errors=None, newline=None)
| Parameter |
Description |
file |
The path or name of the file to open. |
mode |
Specifies the permitted file operations. |
buffering |
Controls buffering behavior. |
encoding |
Specifies text encoding, such as UTF-8. |
errors |
Controls how encoding and decoding errors are handled. |
newline |
Controls newline handling for text files. |
For ordinary text files, explicitly specifying encoding="utf-8" is often a good practice because it makes the intended text encoding clear.
3. Understanding File Modes
A file mode determines what Python can do with an opened file and whether the file must already exist. Choosing the correct mode is important because some modes can overwrite existing content.
| Mode |
Purpose |
File Must Exist? |
Effect on Existing Content |
r |
Read text |
Yes |
Preserves content. |
w |
Write text |
No |
Truncates existing content. |
a |
Append text |
No |
Preserves content and adds data at the end. |
x |
Create a new text file exclusively |
No |
Fails if the file already exists. |
r+ |
Read and write |
Yes |
Preserves content initially; writes can overwrite existing bytes or characters. |
w+ |
Read and write |
No |
Truncates an existing file or creates a new one. |
a+ |
Read and append |
No |
Preserves existing content; writes go to the end. |
rb |
Read binary data |
Yes |
Preserves content. |
wb |
Write binary data |
No |
Truncates existing content. |
ab |
Append binary data |
No |
Adds binary data at the end. |
4. Reading Files with the r Mode
The r mode opens a file for reading. It raises FileNotFoundError if the specified file does not exist.
Example: Reading the Entire File
with open("sample.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)
The read() method returns the file content as a string in text mode. When the file is large, reading everything at once may consume substantial memory.
Reading a Limited Number of Characters
with open("sample.txt", "r", encoding="utf-8") as file:
first_part = file.read(10)
print(first_part)
This reads up to ten characters. In text mode, the argument to read() represents characters, not necessarily bytes.
Reading Line by Line
with open("sample.txt", "r", encoding="utf-8") as file:
for line in file:
print(line.rstrip())
Iterating over a file is memory-efficient for large text files. The rstrip() method removes trailing whitespace, including the line-ending characters.
5. Writing Files with the w Mode
The w mode opens a file for writing. If the file does not exist, Python creates it. If it already exists, its content is truncated when the file is opened.
with open("output.txt", "w", encoding="utf-8") as file:
file.write("Welcome to Python file handling.\n")
file.write("This is a new line.\n")
The write() method writes a string and returns the number of characters written. It does not automatically add a newline, so use \n when you want a line break.
Important: Do not use w when you need to preserve existing content. Opening an existing file in this mode can erase its previous data.
6. Appending Data with the a Mode
The a mode adds new content to the end of a file. It creates the file if it does not exist and preserves its existing content.
with open("activity.log", "a", encoding="utf-8") as file:
file.write("Application started.\n")
file.write("User signed in.\n")
Append mode is useful for logs, audit records, activity histories, and reports that need to accumulate information over time.
To avoid joining new text to the final existing line, include an appropriate newline in the text you append.
7. Creating New Files with the x Mode
The x mode creates a new file only if the path does not already exist. If a file with that name exists, Python raises FileExistsError.
try:
with open("new_report.txt", "x", encoding="utf-8") as file:
file.write("Initial report\n")
except FileExistsError:
print("The report already exists.")
This mode is useful when overwriting an existing file would be undesirable. It provides an exclusive-create operation rather than silently replacing old content.
8. Reading and Writing with Combined Modes
Combined modes permit both reading and writing. Their behavior differs depending on the first character of the mode.
Using r+
with open("sample.txt", "r+", encoding="utf-8") as file:
content = file.read()
print(content)
file.seek(0)
file.write("Updated")
The r+ mode requires an existing file and does not truncate it automatically. The example returns the pointer to the beginning before writing. If the replacement text is shorter than the original content, remaining old characters may still be present.
Using w+
with open("sample.txt", "w+", encoding="utf-8") as file:
file.write("New content")
file.seek(0)
print(file.read())
The w+ mode truncates existing content or creates a new file. After writing, seek(0) moves the pointer to the beginning so the new content can be read.
Using a+
with open("sample.txt", "a+", encoding="utf-8") as file:
file.write("\nAdditional content")
file.seek(0)
print(file.read())
In a+ mode, writes are directed to the end of the file even if the pointer is moved elsewhere for reading. The example moves to the beginning before reading the complete file.
9. Text Mode and Binary Mode
Python handles files in text mode by default. Text mode decodes bytes into strings when reading and encodes strings into bytes when writing. Binary mode works with raw bytes and does not perform text encoding or decoding.
| Feature |
Text Mode |
Binary Mode |
| Examples |
r, w, a |
rb, wb, ab |
| Data type returned by read() |
str |
bytes |
| Encoding |
Uses a text encoding |
No text encoding conversion |
| Common uses |
CSV, TXT, JSON, source code |
Images, PDFs, audio, archives |
Example: Reading Binary Data
with open("photo.jpg", "rb") as file:
image_data = file.read()
print(type(image_data))
print(len(image_data))
The result is a bytes object. Use binary mode when the file must be processed as raw data rather than decoded text.
Example: Copying a Binary File
with open("source.pdf", "rb") as source:
with open("copy.pdf", "wb") as destination:
while True:
chunk = source.read(8192)
if not chunk:
break
destination.write(chunk)
This copies the file in chunks instead of loading the entire file into memory. The destination is opened in wb mode, so an existing destination file will be overwritten.
10. What Is a File Pointer?
A file pointer represents the current position associated with a file object. Read and write operations use this position to determine where data is accessed.
For example, after reading the first five characters of a text file, the next read usually starts after those characters. Moving the pointer lets you revisit an earlier position or jump to another location.
with open("sample.txt", "r", encoding="utf-8") as file:
print(file.read(5))
print(file.read(5))
The first call reads up to five characters. The second call continues from the current position rather than starting from the beginning.
11. Using tell() to Find the Current Position
The tell() method reports the file object's current position. In binary mode, this is a byte offset. In text mode, it is an opaque position value that can be used with seek() to restore a valid text-stream position; it should not generally be interpreted as a simple character count.
with open("sample.txt", "r", encoding="utf-8") as file:
print("Initial position:", file.tell())
data = file.read(4)
print("Read data:", data)
print("Position after reading:", file.tell())
This example displays the initial position, reads four characters, and then reports the position returned by the text stream.
12. Using seek() to Move the File Pointer
The seek() method changes the file position. Its general syntax is:
file.seek(offset, whence=0)
| Argument |
Meaning |
offset |
The position adjustment, interpreted according to the starting point. |
whence=0 |
Seek relative to the beginning of the file. |
whence=1 |
Seek relative to the current position where supported. |
whence=2 |
Seek relative to the end of the file where supported. |
For text files, portable seeking is more restricted than in binary mode. The safest common pattern is seek(0) to return to the beginning, or using a position previously returned by tell(). Nonzero offsets relative to the current position or end are generally not supported for text streams.
Example: Returning to the Beginning
with open("sample.txt", "r", encoding="utf-8") as file:
print(file.read(6))
file.seek(0)
print(file.read(6))
Both reads return the same initial text because seek(0) resets the position to the beginning.
Example: Seeking in Binary Mode
with open("data.bin", "rb") as file:
file.seek(10)
data = file.read(5)
print(data)
This moves to byte offset 10 and reads up to five bytes. Seeking to a position beyond the current end is permitted for many seekable binary files, although a subsequent read returns no data until content is written.
13. Reading a File in Multiple Steps
Small reads can help process a file incrementally. After each read, the pointer moves forward by the amount consumed according to the stream's rules.
with open("sample.txt", "r", encoding="utf-8") as file:
first = file.read(3)
second = file.read(4)
third = file.read()
print("First:", first)
print("Second:", second)
print("Remaining:", third)
The first read returns up to three characters, the second returns up to four more, and the final read returns the remaining content.
14. Reading Lines and Tracking Positions
The methods readline() and readlines() offer different approaches to reading text files.
readline() reads one line at a time.
readlines() reads all remaining lines into a list.
- Iterating directly over the file reads lines progressively and is generally preferable for large files.
with open("students.txt", "r", encoding="utf-8") as file:
position_before = file.tell()
first_line = file.readline()
position_after = file.tell()
print("First line:", first_line.rstrip())
print("Position before:", position_before)
print("Position after:", position_after)
The exact position values depend on the file's encoding and the text stream implementation. Use the values returned by tell() rather than assuming they always equal the number of characters read.
15. Updating Specific File Content
Opening a text file with r+ allows reading and writing without automatic truncation. However, writing at a position replaces existing content from that position onward for the length written; it does not insert text and shift the remaining content to the right.
with open("record.txt", "r+", encoding="utf-8") as file:
file.seek(0)
file.write("NEW")
If the file begins with OLD RECORD, the first characters are replaced, and the remaining characters can still follow the replacement. This may produce NEW RECORD when the replacement length is the same as the replaced portion.
For reliable replacement of a complete text file, a safer pattern is to read the original data, modify it in memory, and write the updated result to a temporary file before replacing the original when appropriate.
16. File Pointer and End-of-File Behavior
When a read operation reaches the end of a file, read() returns an empty string in text mode or empty bytes in binary mode if no data remains. Repeated reads at the end continue returning an empty result until the position changes or new data becomes available through supported operations.
with open("sample.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)
next_content = file.read()
print(repr(next_content)) # Usually '' at end-of-file
The repr() function makes empty strings visible as '', which is useful when debugging file-reading behavior.
17. Using with to Manage Files Safely
The with statement uses a context manager to close the file automatically when the block exits, including when an exception occurs.
with open("notes.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)
This is preferable to manually opening a file and relying on a later close() call. A properly closed file releases system resources and helps ensure buffered data is handled correctly.
18. Handling File Errors
File operations can fail because a path is incorrect, permissions are insufficient, a file already exists, or a device encounters an I/O problem. Use specific exception handling when you can respond meaningfully to the error.
try:
with open("missing.txt", "r", encoding="utf-8") as file:
print(file.read())
except FileNotFoundError:
print("The requested file does not exist.")
except PermissionError:
print("You do not have permission to access this file.")
except OSError as error:
print("A file operation failed:", error)
FileNotFoundError and PermissionError are subclasses of OSError, so the more specific handlers should appear before the general handler.
19. Common Mistakes When Working with File Modes and Pointers
| Mistake |
Why It Is a Problem |
Better Practice |
Using w when intending to append |
Existing file content is truncated. |
Use a when adding content at the end. |
Reading a missing file in r mode |
Python raises FileNotFoundError. |
Check the path or handle the exception. |
| Reading immediately after writing |
The pointer may be at the end. |
Use seek(0) or a saved valid position when appropriate. |
Assuming write() inserts text |
It overwrites data at the current position. |
Rebuild the content or use a separate output file for insertion-style edits. |
| Using text mode for raw binary data |
Encoding conversion can alter or reject data. |
Use binary modes such as rb and wb. |
| Forgetting to close a file |
Resources may remain open and buffered output may not be finalized promptly. |
Prefer with open(...). |
| Assuming text positions are character counts |
Encoded characters and newline handling can make this inaccurate. |
Use positions returned by tell() with supported seek() operations. |
20. Best Practices for File Handling
- Use
with open() so files are closed reliably.
- Choose the least destructive mode that meets the requirement.
- Specify an encoding such as UTF-8 when working with text.
- Use binary mode for images, PDFs, and other raw binary formats.
- Use
tell() and seek() when you need to track or reposition a file stream.
- For large files, process data in chunks or iterate line by line.
- Handle expected errors without hiding unexpected failures.
- Validate file paths and avoid overwriting important data unintentionally.
- Use temporary files and a deliberate replacement strategy when modifying important files.
21. Practical Example: Managing a Student Record File
This example demonstrates creating or appending student records, then reading them back.
def add_student(name, score):
with open("students.txt", "a", encoding="utf-8") as file:
file.write(f"{name},{score}\n")
def display_students():
try:
with open("students.txt", "r", encoding="utf-8") as file:
for line in file:
name, score = line.rstrip("\n").split(",", 1)
print(f"Student: {name}, Score: {score}")
except FileNotFoundError:
print("No student records are available yet.")
add_student("Aarav", 85)
add_student("Meera", 92)
display_students()
The append mode preserves previous records, while read mode displays them. This simple format is suitable for practice; for production applications, consider the csv module to handle commas and quoting correctly.
22. Practice Exercises
- Create a text file and write three lines using
w mode.
- Read the file using
r mode and display its content.
- Append another line using
a mode, then verify that the previous content remains.
- Use
tell() to inspect the current position before and after reading part of a file.
- Use
seek(0) to read the beginning of the file a second time.
- Open an existing file with
x mode and handle the resulting FileExistsError.
- Copy an image or PDF using binary mode and compare the source and destination file sizes.
- Use
r+ to overwrite a short section of a test file and inspect what happens to the remaining content.
23. Mini Project: Text File Activity Tracker
Objective: Build a small application that records activities in a text file and allows the user to view the history.
Requirements
- Use append mode to add new activity records.
- Include a timestamp or sequence number with each record.
- Use read mode to display all saved activities.
- Handle a missing file gracefully.
- Use a context manager for every file operation.
- Optionally, add a feature to read the last few records without loading the entire file into memory.
Sample Implementation
from datetime import datetime
def record_activity(message):
timestamp = datetime.now().isoformat(timespec="seconds")
with open("activity.txt", "a", encoding="utf-8") as file:
file.write(f"{timestamp} - {message}\n")
def show_activities():
try:
with open("activity.txt", "r", encoding="utf-8") as file:
for line in file:
print(line.rstrip())
except FileNotFoundError:
print("No activity has been recorded.")
record_activity("Application launched")
record_activity("Report generated")
show_activities()
This project demonstrates practical use of append mode, read mode, newline handling, context managers, and exception handling.
24. Interview Questions and Answers
Q1. What is a file mode in Python?
A file mode defines how a file is opened and which operations are permitted, such as reading, writing, appending, or binary access.
Q2. What is the difference between w and a?
w truncates an existing file or creates a new one. a preserves existing content and writes new data at the end.
Q3. What does r+ mean?
It opens an existing file for both reading and writing without truncating it automatically.
Q4. What is the purpose of x mode?
It creates a new file exclusively and raises FileExistsError if the target already exists.
Q5. What does tell() do?
It returns the current stream position, which can be used to inspect where file operations are positioned.
Q6. What does seek() do?
It moves the file position to a specified location supported by the stream.
Q7. What is the difference between text and binary modes?
Text mode works with decoded strings and encoding rules. Binary mode works directly with bytes.
Q8. Why is the with statement recommended?
It ensures that the file is closed when the block exits, even if an exception occurs.
Q9. Does write() insert text into the middle of a file?
No. It writes at the current position and can overwrite existing data. Insertion generally requires rebuilding the content or using another file.
Q10. What happens when read() reaches the end of a file?
It returns an empty string in text mode or empty bytes in binary mode when no more data is available.
25. Quick Revision Checklist
r: Read an existing file.
w: Write, truncating an existing file.
a: Append at the end.
x: Create a new file without replacing an existing one.
r+, w+, a+: Combine reading and writing with different file-creation and truncation behaviors.
b: Work with raw bytes.
tell(): Inspect the current stream position.
seek(): Reposition the stream where supported.
with open(): Manage file resources safely.
- Exception handling: Respond to missing files, permission problems, and other I/O failures.
26. Conclusion
Understanding file modes and file pointers is essential for building Python programs that read, create, update, and process persistent data. Selecting the correct mode prevents accidental data loss, while tell() and seek() provide control over a file stream's position. Combine these concepts with context managers, suitable encodings, binary handling when required, and appropriate exception handling to write reliable file-processing applications.
To continue learning Python, explore the Python Training Course, register for a course demo, or visit the JustAcademy website.